﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyStack.Models
{
	public class MyStackRepository
	{

        public User GetUser(int user_id)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
            User owner = db.Users.Single(u => u.UserId == user_id);
            return owner;
        }

        public Story GetStory(int story_id)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
            Story story = db.Stories.Single(s => s.StoryId == story_id);
            return story;
        }

		public StoryView GetStoryView(int storyId)
		{
			MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

			StoryView view = new StoryView();

			Story story = db.Stories.Single(s => s.StoryId == storyId);
			view.Title = story.Title;
			view.Content = story.Content;

			User author = db.Users.Single(a => a.UserId == story.AuthorId);
			view.Author = author.Name;
            view.AuthorId = author.UserId;

            view.StoryId = story.StoryId;

			//	Get the current owner
			var holder = from o in db.Users
						 where o.StackId == story.StackId
						 select o;
			User owner = holder.First();
			view.Owner = owner.Name;
            view.OwnerId = owner.UserId;

			return view;
		}

		/// <summary>
		/// Get the stack for the given user id
		/// </summary>
		public StackView GetStackViewByUser(int stackOwnerId)
		{
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
            StackView sv = new StackView();

            User owner = db.Users.Single(u => u.UserId == stackOwnerId);
            sv.User = owner;

            // old
			var stories = from story in db.Stories
						  where story.StackId == owner.StackId
						  orderby 
							//	Get newest history entry for this story
							(
						    from storyHist in db.Histories
							where storyHist.StoryId == story.StoryId
							orderby storyHist.Timestamp descending
							select storyHist
							).First().Timestamp
							descending
						  select story;

			sv.Stories = stories.ToArray();

            var popped_stories = (from history in db.Histories
                                 where history.UserId == stackOwnerId && 
                                       history.Story.StackId != owner.StackId
                                 //orderby history.Timestamp descending
                                 select history.Story).Distinct().OrderBy(h => h.Timestamp);
            sv.PoppedStories = popped_stories.ToArray().Reverse().ToArray();

			return sv;
		}
		
		/// <summary>
		/// Get the stack of a specified user, no fancy view just
		/// the raw stack
		/// </summary>
		/// <param name="stackOwnerId">User id of the stack owner</param>
		/// <returns>Stack belonging to the specified owner</returns>
		public Stack GetUsersStack(int stackOwnerId)
		{
			MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
			Stack stack = db.Stacks.Single(s => s.UserId == stackOwnerId);

			return stack;
		}

        /// <summary>
        /// Register a new user in MyStack.User table
        /// </summary>
        public int RegisterUser(User user)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
			
            db.Users.InsertOnSubmit(user);
            db.SubmitChanges();
            return user.UserId;
			//	TODO: create stack automatically
        }
        /// <summary>
        /// Create a  stack for a newly registered user
        /// </summary>
        public void CreateStack(int userID)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();
            Stack s = new Stack();
            s.UserId = userID;
            db.Stacks.InsertOnSubmit(s);
            db.SubmitChanges();

            //User user = GetUser(userID);
            User user = db.Users.Single(u => u.UserId == userID);
            user.StackId = s.StackId;
            db.SubmitChanges();
        }

		/// <summary>
		/// Push the given story onto the stack of the specified user
		/// </summary>
		public void Push(int stackOwnerId, Story newStory)
		{
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            // Create the new story
            newStory.AuthorId = stackOwnerId;

			Stack stack = this.GetUsersStack(stackOwnerId);
			newStory.StackId = stack.StackId;
			newStory.Timestamp = DateTime.Now;

			db.Stories.InsertOnSubmit(newStory);
            db.SubmitChanges();

            // insert into history table
            History history = new History();
            history.ActionType = 0;
            history.StackId = stackOwnerId;
            history.UserId = stackOwnerId;
            history.StoryId = newStory.StoryId;
			history.Timestamp = DateTime.Now;
            db.Histories.InsertOnSubmit(history);

            db.SubmitChanges();
		}

        // For the explore stories view. get history of all actions
        public StoriesView[] GetAllStories()
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            
			var views = from entry in db.Histories
						orderby entry.Timestamp descending
						select new StoriesView()
						{
							ActingUser = entry.User.Name,
							ActingUserId = entry.User.UserId,
							Action = this.GetActionString(entry.ActionType),
							Author = db.Users.Single(author => author.UserId == entry.Story.AuthorId).Name,
							AuthorId = db.Users.Single(author => author.UserId == entry.Story.AuthorId).UserId,
							Title = entry.Story.Title,
							StoryId = entry.Story.StoryId,
							SourceUser = entry.Stack.User.Name,
							SourceUserId = entry.Stack.User.UserId,
							StackId = entry.Stack.StackId,
                            Time = this.GetTimeString(entry.Timestamp),
						};
						

            return views.ToArray();
        }

        // For the explore stories view. get history of all actions
        public StoryView[] GetAllPopularStories()
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            var views = from story in db.Histories
                        group story by story.StoryId into g
                        orderby g.Count() descending
                        select g.First().StoryId;

            int[] stories = views.ToArray();
            int cur = 0;
            int num = stories.Length;
            StoryView[] story_views = new StoryView[num];
            foreach (int storyid in stories)
            {
                story_views[cur] = this.GetStoryView(storyid);
                var count = (from story in db.Histories
                            where story.StoryId == storyid
                            select story).Count();
                story_views[cur].Count = count - 1;
                cur++;
            }

            return story_views;
        }

        public string GetTimeString(DateTime time)
        {
            TimeSpan age = DateTime.Now - time;
            if (age.TotalDays > 30)
            {
                int months = (int)(age.TotalDays / 30.0);
                return months.ToString() + " months ago";
            }

            if (age.TotalHours > 24)
            {
                int days = (int)(age.TotalHours / 24.0);
                return days.ToString() + " days ago";
            }

            if (age.TotalMinutes > 60)
            {
                int hours = (int)(age.TotalMinutes / 60);
                return hours.ToString() + " hours ago";
            }

            int minutes = (int)age.TotalMinutes;
            return minutes.ToString() + " minutes ago";
        }

		public string GetActionString(int actionId)
		{
			Actions action = (Actions)actionId;

			string actionString = String.Empty;

			switch (action)
			{
				case Actions.Push:
					actionString = "Pushed";
					break;
				case Actions.Pop:
					actionString = "Popped";
					break;
				default:
					break;
			}

			return actionString;
		}

        public StoriesView[] getUserActivity(int user_id)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            var views = from entry in db.Histories
                        where entry.User.UserId == user_id || entry.Stack.User.UserId == user_id
                        orderby entry.Timestamp descending
                        select new StoriesView()
                        {
                            ActingUser = entry.User.Name,
                            ActingUserId = entry.User.UserId,
                            Action = this.GetActionString(entry.ActionType),
                            Author = db.Users.Single(author => author.UserId == entry.Story.AuthorId).Name,
                            AuthorId = db.Users.Single(author => author.UserId == entry.Story.AuthorId).UserId,
                            Title = entry.Story.Title,
                            StoryId = entry.Story.StoryId,
                            SourceUser = entry.Stack.User.Name,
                            SourceUserId = entry.Stack.User.UserId,
                            StackId = entry.Stack.StackId,
                            Time = this.GetTimeString(entry.Timestamp),
                        };


            return views.ToArray();
        }

        public StoriesView[] getStoryHistory(int story_id)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            var views = from entry in db.Histories
                        where entry.Story.StoryId == story_id
                        orderby entry.Timestamp descending
                        select new StoriesView()
                        {
                            ActingUser = entry.User.Name,
                            ActingUserId = entry.User.UserId,
                            Action = this.GetActionString(entry.ActionType),
                            Author = db.Users.Single(author => author.UserId == entry.Story.AuthorId).Name,
                            AuthorId = db.Users.Single(author => author.UserId == entry.Story.AuthorId).UserId,
                            Title = entry.Story.Title,
                            StoryId = entry.Story.StoryId,
                            SourceUser = entry.Stack.User.Name,
                            SourceUserId = entry.Stack.User.UserId,
                            StackId = entry.Stack.StackId,
                            Time = this.GetTimeString(entry.Timestamp),
                        };


            return views.ToArray();
        }

        public int GetUserIdByName(string name)
        {
            int id = -1;
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

            try
            {
                User owner = db.Users.Single(u => u.Name == name);
                id = owner.UserId;
            }
            catch { }

            return id;
        }
        
        public bool Pop(int user_id, int story_id)
        {
            MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

			User user = db.Users.Single( u => u.UserId == user_id );

			Story story = db.Stories.Single(s => s.StoryId == story_id);
			
			//	Move the story to this user's stack
			int oldStackId = story.StackId;
			story.StackId = user.StackId.Value;
			
            // insert into history
            History history = new History();
            history.ActionType = (int)Actions.Pop;
            history.StackId = oldStackId;  // stack it was popped from
            history.UserId = user_id;  // this user
            history.StoryId = story_id;
			history.Timestamp = DateTime.Now;
            db.Histories.InsertOnSubmit(history);
			
            db.SubmitChanges();
            
			return true;
        }

		public int GetStoryOwner(int storyid)
		{
			MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

			Story story = db.Stories.Single(s => s.StoryId == storyid);

			Stack stack = db.Stacks.Single(stk => stk.StackId == story.StackId);
						
			return stack.UserId;
		}

		public StoriesView GetLatestStory()
		{
			MyStackDataClassesDataContext db = new MyStackDataClassesDataContext();

			var query = from entry in db.Histories
						orderby entry.Timestamp descending
						select new StoriesView()
						{
							ActingUser = entry.User.Name,
							ActingUserId = entry.User.UserId,
							Action = this.GetActionString(entry.ActionType),
							Author = db.Users.Single(author => author.UserId == entry.Story.AuthorId).Name,
							AuthorId = db.Users.Single(author => author.UserId == entry.Story.AuthorId).UserId,
							Title = entry.Story.Title,
							StoryId = entry.Story.StoryId,
							SourceUser = entry.Stack.User.Name,
							SourceUserId = entry.Stack.User.UserId,
							StackId = entry.Stack.StackId,
						};

			return query.First();			
		}
	}
}
